﻿namespace Sofire.Data
{
    using System;
    using System.Data.Common;
    using System.Data.OleDb;
    using System.IO;
    using System.Data;

    /// <summary>
    /// 基于 Miscsoft OleDb 查询与交互的操作引擎。
    /// </summary>
    public class OleDbQuery : QueryEngineBase
    {
        #region Fields

        /// <summary>
        /// 当前 Oledb 数据库的物理路径。该属性一般用于
        /// </summary>
        public string Filename;

        #endregion Fields

        #region Constructors

        /// <summary>
        /// 初始化 <see cref="Sofire.Data.OleDbQuery"/> 的新实例。但并不建议您使用此构造方法。
        /// <para>说明：若必须使用此构造方法，请同时指定 Filename 属性。</para>
        /// </summary>
        /// <param name="connectionString">连接字符串。</param>
        public OleDbQuery(string connectionString)
            : base(QueryEngineProvider.Microsoft_OleDb_After_2007, connectionString)
        {
        }

        /// <summary>
        /// 初始化 <see cref="Sofire.Data.OleDbQuery"/> 的新实例。
        /// </summary>
        /// <param name="oledbProvider"> Miscsoft OleDb 的版本。</param>
        /// <param name="filename"> Miscsoft OleDb 文件路径。</param>
        public OleDbQuery(QueryEngineProvider oledbProvider, string filename)
            : this(oledbProvider, filename, null)
        {
        }

        /// <summary>
        /// 初始化 <see cref="Sofire.Data.OleDbQuery"/> 的新实例。
        /// </summary>
        /// <param name="oledbProvider"> Miscsoft OleDb 的版本。</param>
        /// <param name="filename"> Miscsoft OleDb 文件路径。</param>
        /// <param name="pwd">访问 Miscsoft OleDb 的密码。</param>
        public OleDbQuery(QueryEngineProvider oledbProvider, string filename, string pwd)
        {
            this.Filename = filename;
            string connectionString = "Provider=Microsoft.";
            switch(oledbProvider)
            {
                case QueryEngineProvider.Microsoft_OleDb_Before_2003:
                    connectionString += "Jet.OleDb.4.0";
                    break;
                case QueryEngineProvider.Microsoft_OleDb_After_2007:
                    connectionString += "Ace.OleDb.12.0";
                    break;
                default:
                    throw new ArgumentException("oledbProvider 参数只允许是 Microsoft_Access_2000_2003 或 Microsoft_Access_2007！");
            }

            connectionString += @";Data Source='" + filename + "';";
            if(string.IsNullOrEmpty(pwd))
            {
                connectionString += "Persist Security Info=False;";
            }
            else
            {
                connectionString += "Jet OleDb:DataBase Password='" + pwd + "';";
            }
            base.Initialization(oledbProvider, connectionString);
        }

        #endregion Constructors

        #region Methods

        /// <summary>
        /// 将当前的数据库备份到指定路径。
        /// <para>说明：当前属性 Filename 不存在或拷贝文件失败，都会返回异常对象。否则返回 null 值。</para>
        /// </summary>
        /// <param name="filename">备份文件路径。</param>
        public Exception BackupFile(string filename)
        {
            try
            {
                FileInfo file = new FileInfo(this.Filename);
                if(file.Exists) return new Exception("无法找到要备份的数据库物理路径！");
                file.CopyTo(filename, true);
                return null;
            }
            catch(Exception ex)
            {
                return ex;
            }
        }

        /// <summary>
        /// 创建并返回一个 <see cref="System.Data.OleDb.OleDbCommandBuilder"/> 查询命令生成器。
        /// </summary>
        /// <returns>返回一个查询命令生成器。</returns>
        public override DbCommandBuilder CreateCommandBuilder()
        {
            return new OleDbCommandBuilder();
        }

        /// <summary>
        /// 创建并返回一个 <see cref="System.Data.OleDb.OleDbConnection"/> 数据源。
        /// </summary>
        /// <returns>返回一个数据库的连接。</returns>
        public override DbConnection CreateConnection()
        {
            return new OleDbConnection(this.ConnectionString);
        }

        /// <summary>
        /// 创建并返回一个 <see cref="System.Data.OleDb.OleDbDataAdapter"/> 数据适配器。
        /// </summary>
        /// <param name="command">命令对象。</param>
        /// <returns>返回一个数据适配器。</returns>
        public override DbDataAdapter CreateDataAdapter(DbCommand command)
        {
            return new OleDbDataAdapter(command as OleDbCommand);
        }

        #endregion Methods

        /// <summary>
        /// 描述指定的 <see cref="System.Data.Common.DbParameter"/>。
        /// </summary>
        /// <param name="parameter">一个 <see cref="System.Data.Common.DbParameter"/> 的实例。</param>
        /// <returns>返回参数描述的 <see cref="System.String"/> 值。</returns>
        public override string DescribeParameter(DbParameter parameter)
        {
            var p = parameter as OleDbParameter;
            string desc = p.ParameterName;

            switch(p.Direction)
            {
                case ParameterDirection.InputOutput:
                    desc += " IN OUT";
                    break;
                case ParameterDirection.Output:
                    desc += " OUT";
                    break;
            }
            desc += " " + p.OleDbType;
            switch(p.OleDbType)
            {
                case OleDbType.Char:
                case OleDbType.VarNumeric:
                case OleDbType.Single:
                case OleDbType.Double:
                case OleDbType.Decimal:
                case OleDbType.Numeric:
                case OleDbType.VarChar:
                case OleDbType.Binary:
                case OleDbType.VarBinary:
                    desc += "(" + p.Size + ")";
                    break;
            }
            return desc;
        }
    }
}